/**
 * Copyright 2012 ibiblio
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ibiblio.terasaur.ui

import java.text.Normalizer

class StringCleaner {
    static DEFAULT_WORD_LIMIT = 5
    static DEFAULT_CHAR_LIMIT = 100

    /**
     * Clean a string for inclusion in a url (e.g. item title).
     *
     * - Convert non-alphanumeric characters to spaces
     * - Remove leading and trailing spaces
     * - Remove duplicate spaces
     * - Convert to lowercase
     * - Truncate at n words
     * - Truncate at n characters
     * - Convert spaces to hyphens
     *
     * @param String
     * @param int maxWords
     * @param int maxLength
     * @return String
     */
    public String clean(String input, int maxWords, int maxLength) {
        String s = Normalizer.normalize(input, Normalizer.Form.NFD)
            .replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
            .replaceAll("'", "")
            .replaceAll("[^\\p{Alnum}]+", " ")
            .trim()
            .toLowerCase()
        s = truncate(s, maxWords, maxLength)
        s = s.replaceAll("\\s+", "-")
        return s
    }

    /**
     * Clean a string using default word and length limits
     *
     * @param String input
     * @return String
     */
    public String clean(String input) {
        return clean(input, DEFAULT_WORD_LIMIT, DEFAULT_CHAR_LIMIT)
    }

    /**
     * Truncate a string by first applying a word limit, then a max length
     * limit.  The string is also truncated along word boundaries.  e.g.
     *
     * "this phrase is far too long", 5, 16 --> "this phrase is"
     *
     * For no limit, set max words and/or length to 0.
     *
     * @param String input
     * @param int maxWords
     * @param int maxLength
     */
    private String truncate(String input, int maxWords, int maxLength) {
        if (maxWords < 0) {
            throw new NumberFormatException("Invalid max words value")
        }
        if (maxLength < 0) {
            throw new NumberFormatException("Invalid max length value")
        }

        // Don't bother if no limits are set
        if (maxWords == 0 && maxLength == 0) {
            return input
        }

        List l = input.split(" ")
        List result = []
        int wordCount = 0
        int charCount = 0
        boolean overLimit = false
        for (int i = 0; i < l.size(); ++i) {
            // Update counts
            wordCount += 1
            if (charCount > 0) {
                // Add a space
                charCount += 1
            }
            charCount += l[i].length()

            // Are we over a limit?
            if (maxWords > 0 && wordCount > maxWords) {
                overLimit = true
            }
            if (maxLength > 0 && charCount > maxLength) {
                overLimit = true
            }
            if (overLimit) {
                break
            }

            result.add(l[i])
        }

        return result.join(" ")
    }

}
